package hidra.metaheuristics.mopsocdr.util;

import java.util.ArrayList;
import java.util.Random;

import hidra.jmetal.core.Solution;
import hidra.jmetal.core.SolutionSet;

public class TournamentSelection {

	public static final double K_SELECTION = 0.1; //between 0 and 1

	public Solution executeDF(SolutionSet solutionSet) {
		int size = solutionSet.size();
		int numberLeadersSelected = (int) (solutionSet.size() * K_SELECTION);

		if (size > 2) {
			if (numberLeadersSelected < 2) {
				numberLeadersSelected = size;
			} 

			ArrayList<Integer> valuesSelected = new ArrayList<>();
			Solution collection[] = new Solution[numberLeadersSelected];
			Random rand = new Random();

			for (int i = 0; i < numberLeadersSelected;) {
				int index = rand.nextInt(size);
				if (newValue(valuesSelected, index)) {
					collection[i] = solutionSet.get(index);
					valuesSelected.add(index);
					i++;
				}
			}

			double maxValue = Double.MIN_VALUE;
			int retIndex = -1;

			int i = 0;
			for (Solution sol : collection) {
				double dFactor = sol.getDiversityFactor();
				if (dFactor > maxValue) {
					maxValue = dFactor;
					retIndex = i;
				}
				i++;
			}

			return collection[retIndex];


		}else {
			int randomElement = (int) (Math.random() * size );
			return solutionSet.get(randomElement);
		}
	}

	public Solution executeCD(SolutionSet solutionSet) {
		int size = solutionSet.size();
		int numberLeadersSelected = (int) (solutionSet.size() * K_SELECTION);

		if (size > 2) {
			if (numberLeadersSelected < 2) {
				numberLeadersSelected = 2;
			} 

			ArrayList<Integer> valuesSelected = new ArrayList<>();
			Solution collection[] = new Solution[numberLeadersSelected];
			Random rand = new Random();

			for (int i = 0; i < numberLeadersSelected;) {
				int index = rand.nextInt(size);
				if (newValue(valuesSelected, index)) {
					collection[i] = solutionSet.get(index);
					valuesSelected.add(index);
					i++;
				}
			}

			double maxValue = Double.MIN_VALUE;
			int retIndex = -1;

			int i = 0;
			for (Solution sol : collection) {
				double dFactor = sol.getCrowdingDistance();
				if (dFactor > maxValue) {
					maxValue = dFactor;
					retIndex = i;
				}
				i++;
			}

			return collection[retIndex];


		}else {
			int randomElement = (int) (Math.random() * size );
			return solutionSet.get(randomElement);
		}
	}

	private boolean newValue(ArrayList<Integer> valuesSelected, int index) {
		boolean ret = true;

		for (Integer val : valuesSelected) {
			if (val == index) {
				ret = false;
				break;
			}
		}

		return ret;

	}

}
